//
//  AQNode.swift
//  AQDeal
//
//  Created by zhangjikuan on 2020/11/11.
//  Copyright © 2020 hsgd. All rights reserved.
//

import UIKit


class AQNode: NSObject {

    
}

import Foundation

class Node<Value> {
    var value: Value
    var next: Node?
    
    init(value: Value, next: Node? = nil) {
        self.value = value
        self.next = next
    }
}

extension Node: CustomStringConvertible {
    var description: String {
        guard let next = next else {
            return "\(value)"
        }
        return "\(value) -> " + String(describing: next) + " "
    }
}

struct LinkedList<Value: Comparable> {
    var head: Node<Value>?
    var tail: Node<Value>?
    
    var isEmpty: Bool {
        return head == nil
    }
    
    mutating func push(_ value: Value) {
        head = Node(value: value, next: head)
        if tail == nil {
            tail = head
        }
    }
    
    mutating func append(_ value: Value) {
        copyNodes()
        
        guard !isEmpty else {
            push(value)
            return
        }
        
        tail!.next = Node(value: value)
        tail = tail!.next
    }
    
    func node(at index: Int) -> Node<Value>? {
        var currentNode = head
        var currentIndex = 0
        
        while currentNode != nil && currentIndex < index {
            currentNode = currentNode?.next
            currentIndex += 1
        }
        return currentNode
    }
    
    @discardableResult
    mutating func insert(_ value: Value, after node: Node<Value>) -> Node<Value> {
        copyNodes()
        
        guard tail !== node else {
            append(value)
            return tail!
        }
        
        node.next = Node(value: value, next: node.next)
        return node.next!
    }
    
    @discardableResult
    mutating func pop() -> Value? {
        copyNodes()
        
        defer {
            head = head?.next
            if isEmpty {
                tail = nil
            }
        }
        
        return head?.value
    }
    
    @discardableResult
    mutating func removeLast() -> Value? {
        copyNodes()
        
        guard let head = head, head.next != nil else {
            return pop()
        }
        
        var prev = head
        var current = head
        while let next = current.next {
            prev = current
            current = next
        }
        
        prev.next = nil
        tail = prev
        
        return current.value
    }
    
    @discardableResult
    mutating func remove(after node: Node<Value>) -> Value? {
        copyNodes()
        
        defer {
            if node.next === tail {
                tail = node
            }
            node.next = node.next?.next
        }
        
        return node.next?.value
    }
    
    mutating func copyNodes() {
        guard !isKnownUniquelyReferenced(&head) else {return}
        guard var oldNode = head else {return}
        
        head = Node(value: oldNode.value)
        var newNode = head
        while let nextOldeNode = oldNode.next {
            newNode?.next = Node(value: nextOldeNode.value)
            newNode = newNode?.next
            oldNode = nextOldeNode
        }
        
        tail = newNode
    }
    
    private func printInReverse<T>(_ node: Node<T>?) {
        guard let node = node else {return}
        printInReverse(node.next)
        print(node.value)
    }
    
    func getMiddle<T>(_ list: LinkedList<T>) -> Node<T>? {
        var slow = list.head // define a slow pointer
        var fast = list.head // define a fast pointer
        
        while let nextFast = fast?.next { // move fast poiner
            fast = nextFast.next // move fast pointer again
            slow = slow?.next // move slow pointer
        }
        
        return slow // return slow pointer
    }
    
    mutating func reverse() {
        var prev = head // prev point to head
        var current = head?.next // current point to next
        tail = head // set new tail
        tail?.next = nil // set new tail next nil
        
        while current != nil { // loop until current is nil
            let next = current?.next // find the next node
            current?.next = prev // reverse next pointer
            prev = current // moving prev forward
            current = next // moving next forward
        }
        
        head = prev // since current is nil, new head is prev
    }
    
    mutating func remove(_ value: Value) {
        while let head = head, head.value == value { // keep moving head until it does not equal to value
            self.head = head.next
        }
        
        var prev = head             // prev pointer, point to head
        var current = head?.next   // current pointer, point to next
        
        while let currentNode = current {  // loop through the list
            guard currentNode.value != value else { // if current value = value
                prev?.next = currentNode.next  // prev next point to current next
                current = prev?.next  // set current to prev next
                continue
            }
            
            prev = current      // move prev forward
            current = current?.next // move current forward
        }
        
        tail = prev // set tail as prev, since current is nil, so prev is the last node
    }
}

